package com.wavecoler.coach.bots;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.logging.Logger;

import javax.jdo.PersistenceManager;
import javax.jdo.Query;

import com.wavecoler.coach.objects.Generalization;
import com.wavecoler.coach.objects.Graph;
import com.wavecoler.coach.objects.Node;


import com.google.appengine.api.datastore.Key;
import com.google.wave.api.*;
import com.google.wave.api.event.BlipSubmittedEvent;
import com.google.wave.api.event.DocumentChangedEvent;
import com.google.wave.api.event.Event;
import com.google.wave.api.event.EventType;
import com.google.wave.api.event.FormButtonClickedEvent;
import com.google.wave.api.event.GadgetStateChangedEvent;
import com.google.wave.api.event.WaveletParticipantsChangedEvent;
import com.google.wave.api.event.WaveletSelfAddedEvent;
import com.google.wave.api.impl.EventMessageBundle;
//import com.sun.tools.javac.util.Convert;
import com.wavecoler.coach.objects.RelationNode;
import com.wavecoler.dao.PMF;
import com.wavecoler.professor.dao.GraphDAO;
import com.wavecoler.professor.objects.User;

/*
 * BotSavER, guarda los datos de las entidades y relaciones y atributos colocados en el diagrama.
 * saver.sprint7bot@appspot.com
 * */


public class BotSavER extends AbstractRobot {
  	
	private static final Logger log = Logger.getLogger(BotSavER.class.getName()); //hacer el logger
	private static String graphName;
	public static Graph graph;
	private static User creator;
	private static Map<String, Node> entity = new HashMap<String, Node>(); // Mapa de entidades
	private static Map<String, Node> relation = new HashMap<String, Node>(); // Mapa de relaciones
	private static List<String> atributo = new ArrayList <String> ();//Lista de atributos
	private static Gadget gadget; 
	private static GraphDAO graphDAO = new GraphDAO();
	
	
	@Override
	protected String getRobotName() {
		// TODO Auto-generated method stub
		return "SavER";
	}

	@Override
	public void onWaveletSelfAdded(WaveletSelfAddedEvent event) {
		 Wavelet wave = event.getWavelet();
		 wave.setTitle("");
		//form en un blip para que el usuario escriba el nombre del diagrama
		 Blip blip = wave.getBlip(wave.reply("\n").getBlipId());
		 blip.append("\n");
		 blip.append("\n");
		 blip.append(new FormElement(ElementType.LABEL, "label_name", "Name:"));
		 blip.append(new FormElement(ElementType.INPUT, "name"));
		 blip.append(new FormElement(ElementType.BUTTON, "saveName","Save Name"));
		 blip.append("\n");
		 blip.append("\n");
		 blip.append(new FormElement(ElementType.LABEL, "label_isExpert", "is Expert?"));
		 blip.append(new FormElement(ElementType.CHECK,"isExpert"));
		
	}
	

	@Override
	protected String getRobotProfilePageUrl() {
		return "http://robotcoacher.appspot.com";
	}

	@Override
	public void onGadgetStateChanged(GadgetStateChangedEvent event) {
			log.info("GadgetStateChanged");
			
			Wavelet wave = event.getWavelet();
			Blip blip = event.getBlip();
			gadget = (Gadget) blip.getElements().get(event.getIndex()); // para saber cual gadget
			
			
		
			//Entities
			String entitiesString = gadget.getProperty("entity");
			if (entitiesString != null ){//para que no me marque error y no entre si no se ha ejecutado una cambio en las entities
			log.info("Entity properties : " + gadget.getProperty("entity"));
			String[] arrayEntities = entitiesString.trim().split(",");

			for (int i = 0; i < arrayEntities.length; i++) {

				String[] result2 = arrayEntities[i].trim().split("_");
				String key = result2[0].substring(3);
				String type = "entity";
				String subtype = result2[1].substring(5);
				String name = result2[2].substring(5);
				
				if (!entity.containsKey(key)) {
					if (!name.equals("")) {
						Node ent = new Node(key, name, type,subtype, graph);
						entity.put(key, ent);
						graph.getNodes().add(ent); //guardo el nodo que acabo de crear en la lista de nodos de la graph
						log.info("Guardada la entidad");
						graphDAO.saveNode(graph);
						/*PersistenceManager db = PMF.get().getPersistenceManager();
						db.makePersistent(graph);//se tiene que hacer persistent la graph no los nodos
						db.close();*/
					}

				}
				
			}
	}
			
			//Relations
			String relationString = gadget.getProperty("relation");
			if (relationString != null){ //para que no me marque error y no entre si no se ha ejecutado un cambio en las relations
					
			log.info("Relation property: " + relationString);
			String[] arrayRelations = relationString.trim().split(",");
			
			
			for (int i = 0; i < arrayRelations.length; i++) {
				String[] result2 = arrayRelations[i].trim().split("_");
				String key = result2[0].substring(3);
				List <String> nodesRelation = new ArrayList<String> ();
				String text = result2[(result2.length -1)].substring(5);
				
				log.info("Ent1: (" +result2[1] + "), Ent2: (" + result2[3] + ")");
				
				//para relaciones de dos
				if (!relation.containsKey(key)){
				if (!text.equals("")){
					
					if (!result2[1].substring(4).equals("") && !result2[3].substring(4).equals("")) {
						Node rel = new Node (key,text,"relation",graph);
						
						for (int a = 1; a < (result2.length - 1); a+=2){
							Node ent1 = graph.getNodesByWaveId(result2[a].substring(4));
							String waveId = ent1.getNodeWaveId();
							String card = result2[a+1].substring(5);
						
							RelationNode relNode = new RelationNode(rel,waveId);
							rel.getRelationNodes().add(relNode);
							log.info(nodesRelation.toString());		
							relation.put(key, rel);	
							
						}
						
						log.info(rel.toString());
						graph.getNodes().add(rel);
						graphDAO.saveNode(graph);
						log.info("Guardada la relacion");
				}
			}
				//cuando se agrega lo de la tercera se debe de updatear todavia tenog que hacer eso
		} else if (relation.containsKey(key)){
			//updateNodes(); 
		}
				log.info("Size: " + result2.length);
				
			}
				
		}
			
			//Attributes
			//attribute:  'id:1295305742678_ent:1294787886636_text:Atributo0', 
			String attributeString = gadget.getProperty("attribute");
			if (attributeString != null)
			{
				String[] asAttributes = attributeString.trim().split(",");
				for (int i = 0; i < asAttributes.length; i++) {
					String[] asAttribute = asAttributes[i].trim().split("_");
					String sWaveId = asAttribute[0].substring(3);
					String sEntWaveId = asAttribute[1].substring(4);
					String label = asAttribute[2].substring(5);
					log.info("Label Attribute: " + label);
					//no se estan guardando en el datastore los datos del atributo
					if (!atributo.contains(sWaveId) && !label.equals("")) {
					
						String sParentNode = asAttribute[1].substring(4);
						
						
						Node entAtt = new Node(); //
						entAtt = graph.getNodesByWaveId(sEntWaveId); //
						entAtt.getAttributes().add(sWaveId); //
						log.info("Attribute List: " + entAtt.getAttributes().get(0));
						
						Node att = new Node (sWaveId, label, "attribute", "simple", sParentNode, graph);
						graph.getNodes().add(att);
						atributo.add(sWaveId);
						graphDAO.saveNode(graph);
						log.info("Guardado el atributo");
						
						
					}
				}
			
			}
	}


	@Override
	public void onFormButtonClicked(FormButtonClickedEvent event) {
		SortedMap<Integer, Element> list = event.getBlip().getElements();
		//guarda el nombre de la graph al dar click
		if (event.getButtonName().equals("saveName")){
			
			//si la checkbox esta seleccionada es experto si no no , guardo datos de graph
			if (list.get(9).asElement().getProperty("value").equals("true")){
				saveCreator(event.getWavelet().getCreator(), "Expert");
			}else {
				saveCreator(event.getWavelet().getCreator(), "NotExpert");
			}
			 
			
			graphName = list.get(4).asElement().getProperty("value");
			
			//pone titulo de wave, nombre:usuario
			String user = creator.getUserName();
			graphName = graphName + ":" + user;
			event.getWavelet().setTitle(graphName);
			
			
			Blip blip = event.getBlip();
			blip.all().delete(); //quita todo el contenido del blip con los FormElements
			String gadgetUrl = "http://robot-coach-er.googlecode.com/svn/trunk/public/ERGadget.stable.xml";
			gadget = new Gadget(gadgetUrl);
			event.getWavelet().getRootBlip().append(gadget);
			
//			saveGraph(graphName, creator.getUserEncodedId());
			
			//creo objeto graph con el userId del creador para guardarlo
			
			graphDAO.saveNode(graph);
			/*PersistenceManager db = PMF.get().getPersistenceManager();
			db.makePersistent(graph); 
			db.close();*/ 
			
			
			//agrego el boton de comparar
			blip.append(new FormElement(ElementType.BUTTON, "compare","Compare"));
			blip.append(new FormElement(ElementType.BUTTON, "checkNodes","checkNodes"));
			blip.append(new FormElement(ElementType.BUTTON, "save","save"));
			
		} 
		if (event.getButtonName().equals("compare")){
			compare(event);
		}
		if (event.getButtonName().equals("checkNodes")){
			List<Node> nodeList = graph.getNodes();
			for (int i = 0; i < nodeList.size(); i++)
				log.info("Node : ID:" + nodeList.get(i).getNodeWaveId() + ", Type: " + nodeList.get(i).getType());
		}
		if (event.getButtonName().equals("save")){
			Generalization oGeneralization = new Generalization("generalization", graph);
			log.info(oGeneralization.getLabel());
		}
	}
	
	private void saveGraph(String name, String userID) {
		log.info("savegraph");
		//query para sacar el tipo de usuario del creador y guardar el diagrama con isExpert etc. 
		PersistenceManager db = PMF.get().getPersistenceManager();
		Query query = db.newQuery("select from " + User.class.getName()	+ " where userId == :p1");	
		List <User> user = (List <User>) query.execute(userID);
		User user2 = user.get(0);
		
		log.info(user2.getUserType());
		query.closeAll();
		db.close();
		boolean userType;
		
		if (user2.getUserType().equals("Expert")){
			userType = true;
			graph = new Graph(name, userID, userType);
			
		}else if (user2.getUserType().equals("NotExpert")){
			userType = false;
			graph = new Graph(name, userID, userType);
		}
		
	}
	
	private void saveCreator(String username, String userType) {
		boolean on = false;
		PersistenceManager db = PMF.get().getPersistenceManager();
		Query query = db.newQuery(User.class);
		query.setFilter("userName == userNameParam");
		query.declareParameters("String userNameParam");
	    List<User> users = (List<User>) query.execute(username);
	    query.closeAll();
	    //Note to self: cierra todas las queries y cierra el pm siempre
	    //recorro lista para checar si el creator ya esta en mis usuarios
	    
	    //checar es mas eficiente no traerse toda la entidad sino solo un campo?
	    for (int i=0; i< users.size(); i++) 
		  {

	    		if (username.equals(users.get(i).getUserName())){  
				  creator = users.get(i);
				  on = true;
				  log.info("usuario existente");
				  //si ya esta creator es ese usuario y se prende bandera de que si esta
			  }
		  }
	    // si no esta en la lista creo el nuevo usuario y lo guardo en base de datos
	    if (on == false){
	    	creator = new User(username, userType);
	    	db.makePersistent(creator);
	    	db.close();
	    	log.info("on = false");
	    	log.info(creator.getUserName());
	    }	

	}
	
	private void compare(FormButtonClickedEvent event){
		String nodes = "";
	
		//si No es experto 
		if (graph.isExpert() == false){
			log.info("NotExpert");
			
			//query para sacar la graph del Expert
			PersistenceManager db = PMF.get().getPersistenceManager();
			Query query = db.newQuery("select from "+ Graph.class.getName() + " where isExpert == true");
		    List<Graph> graphExpertList = (List<Graph>) query.execute();
		    query.closeAll();
		    
			Graph graphExpert = graphExpertList.get(0);
			log.info(graphExpert.getGraphName());
			//lista nodos experto
			List<Node> nodesGraphExpert = graphExpert.getNodes();
			log.info("nodesGraphExpert size: " + nodesGraphExpert.size());
			boolean[] checkNodes = new boolean [nodesGraphExpert.size()];
			
			for (int i = 0; i < nodesGraphExpert.size(); i++){
				
				nodes += nodesGraphExpert.get(i).getLabel() + " ";
				checkNodes[i] = false;
				
			}
			event.getWavelet().reply("\n Entities in Profesor's Diagram: " + nodes);
			
			
			
			//lista nodos no experto
			List <Node> listNodes = graph.getNodes();	
			boolean in = false;
			
			
			for (int i = 0; i < listNodes.size(); i++){
				for (int z = 0 ; z < nodesGraphExpert.size() ; z++){
					log.info("NotExpert: " + listNodes.get(i).getLabel());
					log.info("Expert: " + nodesGraphExpert.get(z).getLabel());
					
					if (listNodes.get(i).getLabel().equalsIgnoreCase(nodesGraphExpert.get(z).getLabel())){
						checkNodes[z] = true;
						z = nodesGraphExpert.size() +1;
						in = true;
					}	
					
				}
			if (in == true){
				
				in = false;
				
			} else if (in == false){
				event.getWavelet().reply("\n Extra Entity: " + listNodes.get(i).getLabel());
			}
			
		}
			for (int j = 0; j < checkNodes.length; j++){
				if (checkNodes[j] == false){
					event.getWavelet().reply("\n Missing Entity: " + nodesGraphExpert.get(j).getLabel());
				}	
			}	
		
		}	
	}

	
	
	
	
}

